package kt;

import ie.omk.smpp.Address;
import ie.omk.smpp.AlreadyBoundException;
import ie.omk.smpp.BadCommandIDException;
import ie.omk.smpp.Connection;
import ie.omk.smpp.SMPPException;
import ie.omk.smpp.message.SMPPPacket;
import ie.omk.smpp.message.SMPPProtocolException;
import ie.omk.smpp.message.SubmitSM;
import ie.omk.smpp.message.tlv.Tag;
import ie.omk.smpp.util.ASCIIEncoding;
import ie.omk.smpp.util.GSMConstants;
import ie.omk.smpp.util.Latin1Encoding;
import ie.omk.smpp.util.UCS2Encoding;
import ie.omk.smpp.util.UTF16Encoding;
import ie.omk.smpp.version.VersionException;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;

import kt.dal.DAL;
import kt.smpp.SmppParameter;
import kt.smpp.observer.AsyncObserver;
import kt.smpp.pdu.SMSResponse;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Example class to submit a message to a SMSC using synchronous communication.
 * This class simply binds to the server, submits a message, and then unbinds.
 * 
 * @see ie.omk.smpp.examples.ParseArgs ParseArgs for details on running this
 *      class.
 */
public class SendMTJob implements Job {
	//private Log logger = LogFactory.getLog(SendMTJob.class);
    private static final Logger logger = LogManager.getLogger(SendMTJob.class);
    private SmppParameter parameters = GWConfig.parameters;
    private Connection smscConnection = SMSGWThread.smscCnn;
    
    private static int totalThread = 0;
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		//get list of MT and send MT
		logger.debug("total thread sending MT " + totalThread);
		synchronized (this) {
			if(totalThread > 10) {
				return;
			}
		}
		ArrayList<SMSResponse> Mts = new ArrayList<SMSResponse>();
		synchronized (this) {
			totalThread++;
			Mts = DAL.getMT(GWConfig.parameters.operator, 10);
			DAL.mark4Send(Mts);
		}
		
		//send each MT 1. send to SMSC 2. remove from MT table 3. remove from MO table 4. Save log to MT_LOG/MO_LOG
		for (SMSResponse smsResponse : Mts) {
			sendMT2SMSC(smsResponse);				
		}			
		synchronized (this) {
			totalThread--;
		}		
	}
	
	private void sendMT2SMSC(SMSResponse smsResponse) {
		// 1. update DB status 2. send to SMSC
		try {
			if(logger.isInfoEnabled())
				logger.info("send MT to SMSC: " + smsResponse);
			
//			Connection smscCnn = new Connection(GWConfig.parameters.hostName, GWConfig.parameters.port, true);
//			AsyncObserver asyncObserver = new AsyncObserver();
//			smscCnn.addObserver(asyncObserver);
//			
//			logger.info("Binding to the SMSC...");
//			smscCnn.bind(Connection.TRANSCEIVER, GWConfig.parameters.systemID,
//					GWConfig.parameters.password, GWConfig.parameters.systemType,
//					GWConfig.parameters.sourceTON, GWConfig.parameters.sourceNPI,
//					smsResponse.getServiceNumber());
//			this.smscConnection = smscCnn;
			
            Address destination = new Address(this.parameters.sourceTON, 
            		this.parameters.sourceNPI, smsResponse.getSenderNumber());

            SubmitSM sm = (SubmitSM) this.smscConnection.newInstance(SMPPPacket.SUBMIT_SM);
            sm.setProtocolID(0x00);// for sending flash msg
            sm.setDataCoding(0x10);// for sending flash msg
            sm.setDestination(destination);
            sm.setSource(new Address(GSMConstants.GSM_TON_UNKNOWN,
                    GSMConstants.GSM_NPI_E164, smsResponse.getServiceNumber()));            
            DAL.updateMTStatusAndSeqById(smsResponse.getId(), sm.getSequenceNum(), SMSResponse.DeliveryStatus.SUBMITTING);
            
//            if(!smsResponse.isUnicode()) {
//            	if(smsResponse.getContentType() == SMSResponse.CT_WAP_SI) {
//            		byte[] content = createWappush("your result", smsResponse.getInfo());
//            		sm.setMessage(content);
//            		sm.setEsmClass(64);
//            	} else {
//            		sm.setMessageText(smsResponse.getInfo());
//            	}
//            } else {
//            	//TODO send unicode
//            	logger.info("send unicode message " + smsResponse.getInfo());
//            	//sm.setMessageText(smsResponse.getInfo(), new UCS2Encoding());
//            	sendUnicode(smsResponse.getInfo(), sm.getSource(), sm.getDestination(), sm.getSequenceNum());
//            }
            
//            if(logger.isDebugEnabled()){
//            	logger.debug("submit message: " + sm);
//            }
//          ASCIIEncoding a = new ASCIIEncoding();        
//          sm.setMessage(a.encodeString(smsResponse.getInfo()));
//            sm.setMessageText(smsResponse.getInfo());
//          sm.setMessageText(smsResponse.getInfo(), new UCS2Encoding());            
            sendUnicode(smsResponse.getInfo(), sm.getSource(), sm.getDestination(), sm.getSequenceNum());
            logger.info("submit message: " + sm);
//            this.smscConnection.sendRequest(sm);
//            try {
//				Thread.sleep(1000);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//            this.smscConnection.unbind();
//            this.smscConnection.closeLink();
        } catch (IOException x) {
            logger.error("I/O Exception", x);
        } catch (SMPPException x) {
            logger.error("SMPP Exception", x);
        }
	}
	
	 private void sendUnicode(String msg, Address from, Address to, int seqNo) throws VersionException, BadCommandIDException, SocketTimeoutException, AlreadyBoundException, SMPPProtocolException, ie.omk.smpp.UnsupportedOperationException, IOException {     	 	
		 	UTF16Encoding alphabet = new UTF16Encoding(false);     	 	
     	 	this.smscConnection.setDefaultAlphabet(alphabet);
	        int maxShortMessageLength = 134;
	        int maxSegmentLength = 134;
	        byte[] binaryContent = alphabet.encodeString(msg);
	        int parts = (binaryContent.length < maxShortMessageLength ? 1
	                : (int) Math.ceil(((double) binaryContent.length)
	                        / maxSegmentLength));
	        Integer msgRefNum = new Integer(getNextRefNum());
	        SubmitSM sm;
	        if (parts == 1) {
	            sm = (SubmitSM) this.smscConnection.newInstance(SMPPPacket.SUBMIT_SM);
	            sm.setMessage(binaryContent, alphabet);
	            sm.setSource(from);
	            sm.setDestination(to);
	            sm.setDataCoding(0x08);
	            this.smscConnection.sendRequest(sm);
	        } else {
	            byte[] packet = new byte[maxSegmentLength];
	            for (int i = 0; i < parts; i++) {
	                sm = (SubmitSM) this.smscConnection.newInstance(SMPPPacket.SUBMIT_SM);
	                sm.setSequenceNum(seqNo + i);
	                sm.setSource(from);
	                sm.setDestination(to);
	                sm.setDataCoding(0x08);
	                sm.setOptionalParameter(Tag.SAR_TOTAL_SEGMENTS, new Integer(parts));
	                sm.setOptionalParameter(Tag.SAR_MSG_REF_NUM, msgRefNum);
	                sm.setOptionalParameter(Tag.SAR_SEGMENT_SEQNUM, new Integer(i + 1));
	                if (i == parts - 1) {
	                    int pos = i * maxSegmentLength;
	                    int len = binaryContent.length - pos;
	                    byte[] finalPacket = new byte[len];
	                    System.arraycopy(binaryContent, pos, finalPacket, 0, len);
	                    sm.setMessage(finalPacket, alphabet);
	                } else {
	                    System.arraycopy(binaryContent, i * maxSegmentLength,
	                            packet, 0, maxSegmentLength);
	                    sm.setMessage(packet, alphabet);
	                }
	                logger.info("Sending Submit Packet: " + sm.getMessageText());
	                this.smscConnection.sendRequest(sm);
	            }
	        }
	    }
	    
	    private int nextRefNum = 0;
	    private synchronized int getNextRefNum() {
	        if (nextRefNum >= 65535) { //2 byte positive integer
	            nextRefNum = 0;
	        }
	        return ++nextRefNum;
	    }
}

